#pragma once

#include "njm_system.hpp"
#include "njm_entity.hpp"
#include "njm_component.hpp"

#include <unordered_map>
#include <memory>
#include <cassert>
#include <typeinfo>

namespace njm
{
    class SystemManager
    {
    public:
        SystemManager();
        ~SystemManager();
        void Init();
        void Clear();
        void Update(float deltaTime, Coordinator& coordinator);

        template <typename T>
        std::shared_ptr<T> RegisterSystem()
        {
            const char *typeName = typeid(T).name();
            assert(mSystems.find(typeName) == mSystems.end() && "Registering system more than once.");

            auto system = std::make_shared<T>();
            mSystems.insert({typeName, system});
            return system;
        }

        template <typename T>
        std::shared_ptr<T> GetSystem()
        {
            const char *typeName = typeid(T).name();
            assert(mSystems.find(typeName) != mSystems.end() && "System used before registered.");
            return std::static_pointer_cast<T>(mSystems[typeName]);
        }

        template <typename T>
        void SetSignature(Signature signature)
        {
            const char *typeName = typeid(T).name();
            assert(mSystems.find(typeName) != mSystems.end() && "System used before registered.");
            // 设置System的签名，该签名描述了该System包含了哪些Component
            mSignatures.insert({typeName, signature});
        }

        template <typename T>
        Signature GetSignature()
        {
            const char *typeName = typeid(T).name();
            assert(mSignatures.find(typeName) != mSignatures.end() && "System used before registered.");
            return mSignatures[typeName];
        }

        void EntityDestroyed(Entity entity)
        {
            for (auto const &pair : mSystems)
            {
                auto const &system = pair.second;
                system->mEntities.erase(entity);
            }
        }

        void EntitySignatureChanged(Entity entity, Signature entitySignature)
        {
            for (auto const &pair : mSystems)
            {
                auto const &type = pair.first;
                auto const &system = pair.second;
                auto const &systemSignature = mSignatures[type];

                if ((entitySignature & systemSignature) == systemSignature)
                { // 如果Entity包含了System所需的所有Component
                    system->mEntities.insert(entity);
                }
                else
                { // 否则删除该Entity,因为此时System需要的某些Component没有被该Entity包含,此时System无法处理该Entity
                    system->mEntities.erase(entity);
                }
            }
        }

        template <typename T>
        void AddEntityToSystem(Entity entity)
        {
            const char *typeName = typeid(T).name();
            assert(mSystems.find(typeName) != mSystems.end() && "System used before registered.");
            auto system = std::static_pointer_cast<T>(mSystems[typeName]);
            system->mEntities.insert(entity);
        }

        template <typename T>
        void RemoveEntityFromSystem(Entity entity)
        {
            const char *typeName = typeid(T).name();
            assert(mSystems.find(typeName) != mSystems.end() && "System used before registered.");
            auto system = std::static_pointer_cast<T>(mSystems[typeName]);
            system->mEntities.erase(entity);
        }

    private:
        // 包含所有的签名
        std::unordered_map<const char *, Signature> mSignatures{};
        // 包含所有的System
        std::unordered_map<const char *, std::shared_ptr<System>> mSystems{};
    };
}